﻿#include "p2p_download.h"
#include <QFile>
#include <tcp_client.h>
#include <QTime>

P2P_Download::P2P_Download(QObject *parent, tcp_meta &tm)//tm传入的是在线的文件分享者的ip地址并与其建立tcp连接。
    :QTcpSocket(parent)
{
    status = true;
    flag=true;//flase则终止下载
    port = tm.port + 1;//服务器的端口号，这边默认为8011
    ServerIP = new QHostAddress;
    ServerIP->setAddress(tm.ip);//设置服务器的IP地址
    UserName = tm.owner;
    Dfilepath = tm.filepath;
    Dfilename = tm.filename;
    filesize = tm.size;
    breakpoint=tm.breakpoint;
}

bool P2P_Download::start_as_client(QString dirname){
    qDebug()<<"start_as_client被调用了";
    if(dirname == ""){//如果要下载的任务为空，则退出
        return false;
    }
    Dirname = dirname;//设置本地保存的地址
    connect(this,SIGNAL(connected()),this,SLOT(ClientConnected()));//将tcp连接成功时的函数进行绑定
    connect(this,SIGNAL(disconnected()),this,SLOT(ClientDisconnected()));//tcp连接断开
    connect(this,SIGNAL(readyRead()),this,SLOT(ClientDataReceived()));//接收到服务端传来的数据的处理

    connectToHost(*ServerIP,port);
    return true;
}

void P2P_Download::StopConnected(){
//    disconnectFromHost();//主动断开连接
    qDebug() << "点击停止 此时进度为" << progress ;
    flag=false;
}

void P2P_Download::ClientConnected(){//与p2p服务器的tcp连接成功建立，开始发送要下载的文件所在路径
    QString msg = "#";
    QString slen = QString::number(Dfilepath.length());
    for(int i = slen.length(); i < 10; ++i){//如果文件的路径长度不足10个字符，填充到十个
        slen = "0" + slen;
    }
    msg = msg + slen + "#"+ Dfilepath +"#"+breakpoint;//这里将路径用##包裹，便于服务器接收到请求时进行处理
    write(msg.toLatin1(), msg.length());
}



#define PAK_ERR "PKE"
#define FP_ERR  "FPE"
#define SUCC    "SUC"
void P2P_Download::ClientDataReceived(){//接收到p2p服务器发送的响应后进行处理
    if(bytesAvailable() >= 3){//如果响应大于等于三个字符，说明数据是正确的，三个字符的情况是服务器的响应状态码，文件成功还是失败传输
        char buf[256];

        read(buf, 3);
        QString msg = buf;
        if(msg.mid(0,3) == PAK_ERR){//包错误

        }
        else if(msg.mid(0,3) == FP_ERR){//文件打开失败（文件路径错误，或者其他原因）

        }
        else if(msg.mid(0,3) == SUCC){//文件开始发送，客户端开始接收
            QFile dfile(Dirname + Dfilename);//新建文件用于存储下载的文件
            if(breakpoint == "-1"){//初次下载文件
            QFile dlog("C:/Qt/p2plog/"+Dfilename+"log");//创建文件下载记录日志

            qDebug() << Dirname + Dfilename;
            qDebug() <<Dirname+"log/"+Dfilename+"log";

            qint64 tsz = 0;//记录已经下载好的文件大小
            if(breakpoint == "-1"){
                tsz = 0;//第一次下载文件
                breakpoint = "0";
            }else{
                tsz = 256*breakpoint.toInt();
                qDebug()<< tsz;
            }
            dfile.open(QIODevice::ReadWrite);
            dlog.open(QIODevice::ReadWrite);

                for(int i = breakpoint.toInt(); i < filesize / 256; ++i){//开始下载文件，一块一块下载
                    while(bytesAvailable() < 256){ //整的块也就是慢256字节的块开始下载
                        qDebug()<< "循环一";
                        if(!waitForReadyRead(9000)){//用于等待从套接字中读取到数据，超时时间为3秒，如果3秒后还没有收到数据，就超时报错，断开与服务端的连接
                            qDebug() << "timeout";
                            disconnectFromHost();
                            status = false;
                            return;
                        }
                    }

                    if(!dfile.isOpen()){
                        dfile.open(QIODevice::Append);
                    }

                    if(!dlog.isOpen()){
                        dlog.open(QIODevice::Append);
                    }

             if(dfile.isOpen()){//开始往文件中写东西
                    QTime _Timer = QTime::currentTime().addMSecs(1000);//1s
                        while( QTime::currentTime() < _Timer );

                    read(buf, 256);//从tcp中读取文件数据，并写入到本地文件中

                    dfile.write(buf, 256);

                    dfile.close();//关闭文件，保存块数据

                    tsz = tsz + 256;
                    progress = tsz * 100 / filesize;//设置下载的进度
                    qDebug() << bytesAvailable();
                    qDebug() << progress;
                    breakpoint=QString::number(i);;//设置全局变量breakpoint
                    }

             if(dlog.isOpen()){
             QString logMsg="file progress:"+QString::number(progress)+";"+"download block:"+breakpoint+";"+"loader:"+"user"+";"+"owner:"+UserName+";"+"filename:"+Dfilename+";\n";
             dlog.write(logMsg.toUtf8());
             dlog.close();
             }

                }

                while(bytesAvailable() < (filesize % 256)){
                    qDebug()<< "循环二";
                    if(!waitForReadyRead(9000)){
                        qDebug() << "timeout";
                        disconnectFromHost();
                        status = false;
                        return;
                    }
                }

                if(!dfile.isOpen()){
                    dfile.open(QIODevice::Append);
                }
                if(!dlog.isOpen()){
                    dlog.open(QIODevice::Append);
                }

           if(dfile.isOpen()){//开始往文件中写东西
                read(buf, filesize % 256);
                dfile.write(buf, filesize % 256);
                dfile.close();//关闭文件，保存块数据
                progress = 100;
                qDebug() << progress;
                breakpoint=QString::number((filesize / 256));;//最后一块分区的分片位置
                }

           if(dlog.isOpen()){
           QString logMsg="file progress:"+QString::number(progress)+";"+"download block:"+breakpoint+"#\n";
           dlog.write(logMsg.toUtf8());
           dlog.close();
           }
         }else{//断点续传
                qint64 tsz = 0;//记录已经下载好的文件大小
                    tsz = 256*breakpoint.toInt();
                    qDebug()<< tsz;
                dfile.open(QIODevice::Append);

                    for(int i = breakpoint.toInt(); i < filesize / 256; ++i){//开始下载文件，一块一块下载
                        while(bytesAvailable() < 256){ //整的块也就是慢256字节的块开始下载
                            qDebug()<< "循环一";
                            if(!waitForReadyRead(9000)){//用于等待从套接字中读取到数据，超时时间为3秒，如果3秒后还没有收到数据，就超时报错，断开与服务端的连接
                                qDebug() << "timeout";
                                disconnectFromHost();
                                status = false;
                                return;
                            }
                        }

                        if(!dfile.isOpen()){
                            dfile.open(QIODevice::Append);
                        }

                 if(dfile.isOpen()){//开始往文件中写东西
                        QTime _Timer = QTime::currentTime().addMSecs(1000);//1s
                            while( QTime::currentTime() < _Timer );

                        read(buf, 256);//从tcp中读取文件数据，并写入到本地文件中

                        dfile.write(buf, 256);

                        dfile.close();//关闭文件，保存块数据

                        tsz = tsz + 256;
                        progress = tsz * 100 / filesize;//设置下载的进度
                        qDebug() << bytesAvailable();
                        qDebug() << progress;
                        breakpoint=QString::number(i);;//设置全局变量breakpoint
                        }
                       }

                    while(bytesAvailable() < (filesize % 256)){
                        qDebug()<< "循环二";
                        if(!waitForReadyRead(9000)){
                            qDebug() << "timeout";
                            disconnectFromHost();
                            status = false;
                            return;
                        }
                    }

                    if(!dfile.isOpen()){
                        dfile.open(QIODevice::Append);
                    }

               if(dfile.isOpen()){//开始往文件中写东西
                    read(buf, filesize % 256);
                    dfile.write(buf, filesize % 256);
                    dfile.close();//关闭文件，保存块数据
                    progress = 100;
                    qDebug() << progress;
                    breakpoint=QString::number((filesize / 256));;//最后一块分区的分片位置
                    }
   }
            status = true;
            breakpoint=QString::number(-1);//下载完成，没有异常中断则设置为-1
            disconnectFromHost();//下载完成，与p2p的服务端断开连接
               }
            }
         }


void P2P_Download::ClientDisconnected(){//异常中断则更新服务器数据库的信息

}

P2P_Download::~P2P_Download(){
    this->close();
}
